<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>扫雷游戏</title>
  <style>
    body { font-family: Arial, sans-serif; text-align: center; margin: 20px; }
    #game { display: inline-block; }
    .row { display: flex; }
    .cell {
      width: 30px; height: 30px;
      border: 1px solid #888;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      user-select: none;
      font-weight: bold;
    }
    .cell.revealed { background: #ddd; cursor: default; }
    .cell.mine { background: red; }
    .cell.flagged::after { content: '🚩'; }
  </style>
</head>
<body>
  <h1>扫雷游戏</h1>
  <div>
    <label>行：</label><input id="rows" type="number" value="10" min="5" max="20">
    <label>列：</label><input id="cols" type="number" value="10" min="5" max="20">
    <label>地雷：</label><input id="mines" type="number" value="10" min="1" max="100">
    <button id="startBtn">开始游戏</button>
  </div>
  <div id="game"></div>
  <script>
    const gameEl = document.getElementById('game');
    const startBtn = document.getElementById('startBtn');
    startBtn.addEventListener('click', initGame);

    function initGame() {
      const rows = parseInt(document.getElementById('rows').value);
      const cols = parseInt(document.getElementById('cols').value);
      const mines = parseInt(document.getElementById('mines').value);
      gameEl.innerHTML = '';
      const grid = createGrid(rows, cols, mines);
      renderGrid(grid, rows, cols);
    }

    function createGrid(r, c, m) {
      const total = r * c;
      const minePositions = new Set();
      while (minePositions.size < m) {
        minePositions.add(Math.floor(Math.random() * total));
      }
      const grid = Array(r).fill().map(() => Array(c).fill({}));
      for (let i = 0; i < r; i++) {
        for (let j = 0; j < c; j++) {
          const idx = i * c + j;
          const isMine = minePositions.has(idx);
          grid[i][j] = { mine: isMine, revealed: false, flagged: false, count: 0 };
        }
      }
      for (let i = 0; i < r; i++) {
        for (let j = 0; j < c; j++) {
          if (!grid[i][j].mine) {
            grid[i][j].count = countMines(grid, i, j);
          }
        }
      }
      return grid;
    }

    function countMines(grid, x, y) {
      let count = 0;
      for (let dx = -1; dx <= 1; dx++) for (let dy = -1; dy <= 1; dy++) {
        if (dx===0 && dy===0) continue;
        const nx = x + dx, ny = y + dy;
        if (nx>=0 && nx<grid.length && ny>=0 && ny<grid[0].length && grid[nx][ny].mine) count++;
      }
      return count;
    }

    function renderGrid(grid, r, c) {
      for (let i = 0; i < r; i++) {
        const rowEl = document.createElement('div');
        rowEl.className = 'row';
        for (let j = 0; j < c; j++) {
          const cell = document.createElement('div');
          cell.className = 'cell';
          cell.addEventListener('click', () => onCellClick(grid, i, j));
          cell.addEventListener('contextmenu', e => { e.preventDefault(); onCellRightClick(grid, i, j); });
          rowEl.appendChild(cell);
        }
        gameEl.appendChild(rowEl);
      }
    }

    function onCellClick(grid, x, y) {
      const cell = grid[x][y];
      if (cell.flagged || cell.revealed) return;
      cell.revealed = true;
      updateCellDisplay(grid, x, y);
      if (cell.mine) {
        revealAllMines(grid);
        alert('游戏结束！你踩到地雷了！');
      } else if (cell.count === 0) {
        revealNeighbors(grid, x, y);
      }
    }

    function onCellRightClick(grid, x, y) {
      const cell = grid[x][y];
      if (cell.revealed) return;
      cell.flagged = !cell.flagged;
      updateCellDisplay(grid, x, y);
    }

    function updateCellDisplay(grid, x, y) {
      const rows = grid.length, cols = grid[0].length;
      const cellEls = gameEl.querySelectorAll('.cell');
      const index = x * cols + y;
      const el = cellEls[index];
      const data = grid[x][y];
      el.classList.toggle('revealed', data.revealed);
      el.classList.toggle('flagged', data.flagged);
      if (data.revealed) {
        if (data.mine) {
          el.textContent = '💣';
          el.classList.add('mine');
        } else if (data.count > 0) {
          el.textContent = data.count;
        }
      } else {
        el.textContent = '';
      }
    }

    function revealNeighbors(grid, x, y) {
      for (let dx = -1; dx <= 1; dx++) for (let dy = -1; dy <= 1; dy++) {
        const nx = x + dx, ny = y + dy;
        if (nx>=0 && nx<grid.length && ny>=0 && ny<grid[0].length) {
          if (!grid[nx][ny].revealed && !grid[nx][ny].mine) {
            grid[nx][ny].revealed = true;
            updateCellDisplay(grid, nx, ny);
            if (grid[nx][ny].count === 0) revealNeighbors(grid, nx, ny);
          }
        }
      }
    }

    function revealAllMines(grid) {
      for (let i=0;i<grid.length;i++) for (let j=0;j<grid[0].length;j++) {
        if (grid[i][j].mine) {
          grid[i][j].revealed = true;
          updateCellDisplay(grid, i, j);
        }
      }
    }
  </script>
</body>
</html>
